package com.javaspeak.designpatterns.go4.behavioural.mediator;

import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentSkipListSet;

/**
 * This mediator is central to the Mediator pattern.
 * <p>
 * The ChatMediator mediates between the ChatUsers.  Only the ChatMediator
 * has a references to all consumers and producers.  In this example the
 * ChatUsers are both consumers and producers: they can both send and receive
 * messages.  A ChatUser sends and receives a message via the ChatMediator.
 *
 * @author John Dickerson
 */
public class ChatMediatorImpl implements ChatMediator {

    private Set<String> groups = new ConcurrentSkipListSet<String>();

    private Map<String, Set<ChatUser>> chatUsersByGroup =
        new ConcurrentHashMap<String, Set<ChatUser>>();


    /* (non-Javadoc)
     * @see com.javaspeak.designpatterns.go4.behavioural.mediator.
     *      ChatMediator#getGroups()
     */
    @Override
    public String[] getGroups() {

        return groups.toArray( new String[]{} );
    }


    /* (non-Javadoc)
     * @see com.javaspeak.designpatterns.go4.behavioural.mediator.
     *      ChatMediator#createNewGroup(java.lang.String)
     */
    @Override
    public boolean createNewGroup( String groupName ) {

        if ( groups.contains( groupName ) ) {

            return false;
        }
        else {

            groups.add( groupName );
            return true;
        }
    }


    /* (non-Javadoc)
     * @see com.javaspeak.designpatterns.go4.behavioural.mediator.
     *      ChatMediator#subscribeToGroup(java.lang.String, com.javaspeak.
     *              designpatterns.go4.behavioural.mediator.ChatUser)
     */
    @Override
    public void subscribeToGroup( String group, ChatUser chatUser ) {

        Set<ChatUser> groupChatUsers = chatUsersByGroup.get( group );

        if ( groupChatUsers == null ){

            groupChatUsers = new ConcurrentSkipListSet<ChatUser>();
            chatUsersByGroup.put( group, groupChatUsers );
        }

        groupChatUsers.add( chatUser );
    }


    /* (non-Javadoc)
     * @see com.javaspeak.designpatterns.go4.behavioural.mediator.
     *      ChatMediator#sendMessage(java.lang.String, com.javaspeak.
     *          designpatterns.go4.behavioural.mediator.ChatUser,
     *              java.lang.String)
     */
    @Override
    public void sendMessage( String groupName, ChatUser chatUser, String message ) {

        Set<ChatUser> groupChatUsers = chatUsersByGroup.get( groupName );

        if ( groupChatUsers.contains( chatUser ) ) {

            for ( ChatUser groupChatUser : groupChatUsers ){

                if ( ! groupChatUser.equals( chatUser ) ){

                    groupChatUser.receiveMessage(
                            groupName, chatUser.getUserId(), message );
                }
            }
        }
    }
}
